package com.echo.boot.utils;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.ECPublicKey;

/**
 * Created with IntelliJ IDEA
 * Created By CQ
 * Date: 2020/3/28
 * Time: 11:30
 *
 * @author Administrator
 * 签名算法
 * <p>
 * 我们使用非对称加密算法的时候，对于一个公钥-私钥对，通常是用公钥加密，私钥解密
 * 如果使用私钥加密，公钥解密是否可行呢？实际上是完全可行的。
 * 私钥是保密的，而公钥是公开的，用私钥加密，那相当于所有人都可以用公钥解密。这个加密有什么意义？
 * 这个加密的意义在于，如果小明用自己的私钥加密了一条消息，比如小明喜欢小红，然后他公开了加密消息，由于任何人都可以用小明的公钥解密，从而使得任何人都可以确认小明喜欢小红这条消息肯定是小明发出的，其他人不能伪造这个消息，小明也不能抵赖这条消息不是自己写的。
 * <p>
 * 因此，私钥加密得到的密文实际上就是数字签名，要验证这个签名是否正确，只能用私钥持有者的公钥进行解密验证。使用数字签名的目的是为了确认某个信息确实是由某个发送方发送的，任何人都不可能伪造消息，并且，发送方也不能抵赖。
 * 常用数字签名算法有：
 * RSA 签名
 * MD5withRSA
 * SHA1withRSA
 * SHA256withRSA
 * <p>
 * DSA签名 DSA只能配合SHA使用
 * SHA1withDSA
 * SHA256withDSA
 * SHA512withDSA
 * <p>
 * ECDSA签名
 * Key size must be at least 112 bits
 * Key size must be at most 571 bits
 * SHA1withECDSA
 * SHA256withECDSA
 * SHA384withECDSA
 * SHA512withECDSA
 */
public class SignatureUtils {
    public static void main(String[] args) throws GeneralSecurityException, UnsupportedEncodingException {
        // 生成RSA公钥/私钥:
//        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
//        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DSA");
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC");
//        kpGen.initialize(1024);
        kpGen.initialize(571);
        KeyPair kp = kpGen.generateKeyPair();
        PrivateKey sk = kp.getPrivate();
        PublicKey pk = kp.getPublic();

        // 待签名的消息:
        byte[] message = "Hello, I am Bob!".getBytes(StandardCharsets.UTF_8);

        // 用私钥签名:
//        Signature s = Signature.getInstance("SHA1withRSA");
//        Signature s = Signature.getInstance("SHA1withDSA");
        Signature s = Signature.getInstance("SHA1withECDSA");
        s.initSign(sk);
        s.update(message);
        byte[] signed = s.sign();
        System.out.println(String.format("signature: %x", new BigInteger(1, signed)));

        // 用公钥验证:
//        Signature v = Signature.getInstance("SHA1withRSA");
//        Signature v = Signature.getInstance("SHA1withDSA");
        Signature v = Signature.getInstance("SHA1withECDSA");
        v.initVerify(pk);
        v.update(message);
        boolean valid = v.verify(signed);
        System.out.println("valid? " + valid);
    }

    public static void testOther() {

    }
}
